package org.ofdrw.sign.signContainer;

import org.bouncycastle.asn1.DERBitString;
import org.bouncycastle.asn1.gm.GMObjectIdentifiers;
import org.bouncycastle.jcajce.provider.digest.SM3;
import org.ofdrw.gm.ses.v4.SES_Signature;
import org.ofdrw.gm.ses.v4.SESeal;
import org.ofdrw.gm.ses.v4.TBS_Sign;
import org.ofdrw.sign.SigType;
import org.ofdrw.sign.timestamp.TimeStampHook;

import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.security.cert.Certificate;

public class SESV4ContainerV2 {

    /**
     * 电子印章
     */
    private final SESeal seal;

    /**
     * 签章使用的证书
     */
    private final Certificate certificate;

    /**
     * 时间戳hook对象
     */
    private TimeStampHook timeStampHook;

    public SESV4ContainerV2(SESeal seal, Certificate signCert) {
        this.seal = seal;
        this.certificate = signCert;
    }

    public SESV4ContainerV2(SESeal seal, Certificate signCert, TimeStampHook timeStampHook) {
        this.seal = seal;
        this.certificate = signCert;
        this.timeStampHook = timeStampHook;
    }

    public MessageDigest getDigestFnc() {
        return new SM3.Digest();
    }

    /**
     * @param toSign 待p1签名的值
     * @param p1     toSign 私钥签名结果
     * @return
     * @throws IOException
     * @throws GeneralSecurityException
     */
    public byte[] sign(TBS_Sign toSign, byte[] p1) throws IOException, GeneralSecurityException {

        SES_Signature signature = new SES_Signature().setToSign(toSign).setCert(certificate)
                .setSignatureAlgID(GMObjectIdentifiers.sm2sign_with_sm3).setSignature(p1);

        if (timeStampHook != null) {
            byte[] timeStamp = timeStampHook.apply(p1);
            if (timeStamp != null) {
                signature.setTimeStamp(new DERBitString(timeStamp));
            }
        }

        return signature.getEncoded("DER");
    }

    public byte[] getSeal() throws IOException {
        return seal.getEncoded("DER");
    }

    public SigType getSignType() {
        return SigType.Seal;
    }

}
